package com.maxlen.admin.security;

import com.alibaba.fastjson.JSONObject;
import com.maxlen.admin.entity.bo.LoginDetailsBo;
import com.maxlen.common.constant.MemberConstant;
import com.maxlen.common.exception.ExceptionCode;
import com.maxlen.common.utils.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 重写 attemptAuthentication() 前端传来的是 Json 格式，所以重写此方法通过 Json 来解析参数
 * 重写 successfulAuthentication() 登录成功后调用此方法，重写此方法将信息存入 redis ，并生成 token 返回给前端
 * 重写 unsuccessfulAuthentication() 判断传来的类是哪个类，就返回给前端相应的提示
 */
public class CustomUsernamePasswordFilter extends AbstractAuthenticationProcessingFilter {

    private StringRedisTemplate redisTemplate;

    public CustomUsernamePasswordFilter(AntPathRequestMatcher antPathRequestMatcher, AuthenticationManager authenticationManager, StringRedisTemplate redisTemplate) {
        super(antPathRequestMatcher, authenticationManager);
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String s = bufferedReader.readLine();
            JSONObject jsonObject = JSONObject.parseObject(s);
            String username = jsonObject.getString("username");
            String password = jsonObject.getString("password");
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
            return this.getAuthenticationManager().authenticate(token);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        LoginDetailsBo loginDetailsBo = (LoginDetailsBo) authResult.getPrincipal();
        RedisUtils.set(redisTemplate, MemberConstant.MEMBER_LOGIN + loginDetailsBo.getAdmin().getId().toString(), loginDetailsBo);
        String token = JwtUtils.getJwtToken(loginDetailsBo.getAdmin().getId().toString(), loginDetailsBo.getAdmin().getUsername());
        ResponseUtils.out(response, R.ok().put("data", token));
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        ExceptionCode result = null;
        if (failed instanceof AccountExpiredException) {
            //账号过期
            result = ExceptionCode.USER_ACCOUNT_EXPIRED;
        } else if (failed instanceof BadCredentialsException) {
            //密码错误
            result = ExceptionCode.USER_CREDENTIALS_ERROR;
        } else if (failed instanceof CredentialsExpiredException) {
            //密码过期
            result = ExceptionCode.USER_CREDENTIALS_EXPIRED;
        } else if (failed instanceof DisabledException) {
            //账号不可用
            result = ExceptionCode.USER_ACCOUNT_DISABLE;
        } else if (failed instanceof LockedException) {
            //账号锁定
            result = ExceptionCode.USER_ACCOUNT_LOCKED;
        } else if (failed instanceof InternalAuthenticationServiceException || failed instanceof UsernameNotFoundException) {
            //用户不存在
            result = ExceptionCode.USER_ACCOUNT_NOT_EXIST;
        }else{
            //其他错误
            result = ExceptionCode.UNKNOWN_EXCEPTION;
        }
        ResponseUtils.out(response, R.error().put("data", result));
    }
}
